package com.jsm.tf.net.command;

import com.google.common.collect.Maps;
import com.jsm.tf.net.message.Message;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

@Component
public class CommandFactory implements InitializingBean {
    @Autowired
    private List<Command> commands;
    private Map<Class, Command> commandMap = Maps.newHashMap();


    public <T extends Message> void register(Class<T> clazz, Command<T> command) {
        commandMap.put(clazz, command);
    }

    public <T extends Message> Command build(Class<T> clazz) {
        return commandMap.get(clazz);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        for (Command command : commands) {
            Class<?> t = getInterfaceT(command, 0);
            commandMap.put(t,command);
        }
    }

    public static Class<?> getInterfaceT(Object o, int index) {
        Type[] types = o.getClass().getGenericInterfaces();
        ParameterizedType parameterizedType = (ParameterizedType) types[index];
        Type type = parameterizedType.getActualTypeArguments()[index];
        return checkType(type, index);

    }
    private static Class<?> checkType(Type type, int index) {
        if (type instanceof Class<?>) {
            return (Class<?>) type;
        } else if (type instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) type;
            Type t = pt.getActualTypeArguments()[index];
            return checkType(t, index);
        } else {
            String className = type == null ? "null" : type.getClass().getName();
            throw new IllegalArgumentException("Expected a Class, ParameterizedType"
                    + ", but <" + type + "> is of type " + className);
        }
    }
}
